#pragma once
#include <sstream>
#include <deque>
#include <vector>
#include <string>

#include "basictypes.h"

NAMESPACE_BEGIN(kog);

class serial
{
public:
	serial(void) {}
	~serial(void) {}
//private:
//	serial(const serial&);
//	serial& operator=(const serial&);
public:
	template<typename _Char> serial& append(const std::basic_string<_Char>& str)
	{
		size_t _L = str.length() * sizeof(_Char);
		append(_L);
		//_oss.write(str.c_str(), _L);
		const char* ptr = (const char*)str.c_str();
		_oss.insert(_oss.end(), ptr, ptr + _L);
		return *this;
	}

	template<typename _T> serial& append(const _T& v)
	{
		size_t _S = sizeof(v);
		//_oss.write((const char*)&v, _S);
		const char* ptr = (const char*)&v;
		_oss.insert(_oss.end(), ptr, ptr + _S);
		return *this;
	}

	serial& append(serial& other)
	{
		//_oss<<other._oss.str();
		_oss.insert(_oss.end(), other._oss.begin(), other._oss.end());
		return *this;
	}

	// don't support char ptr, see unserial
	template<typename _T> serial& append(const _T*);
	template<> serial& append<char>(const char* str);
	template<> serial& append<wchar_t>(const wchar_t* str);
public:
	size_t getbuffer(std::string& buf)
	{
		buf.clear();
		buf.insert(buf.end(), _oss.begin(), _oss.end());
		//buf = _oss.str();
		return buf.size();
	}
private:
	//std::ostringstream _oss;
	std::deque<char> _oss;
};

class unserial
{
public:
	unserial(const char* buf, size_t L)
		: _pstart(buf)
		, _pcur(buf)
		, _leftsize(L)
	{
	}
public:
	template<typename _Char> unserial& getvalue(std::basic_string<_Char>& str)
	{
		size_t _L = 0;
		getvalue<size_t>(_L);
		if (_leftsize < _L) throw std::runtime_error("outof range");
		else if (_L % sizeof(_Char) != 0) throw std::runtime_error("invalidate string object!");
		std::basic_string<_Char> tmp((const _Char*)_pcur, ((const _Char*)_pcur) + _L / sizeof(_Char));
		str.swap(tmp);
		_pcur += _L;
		_leftsize -= _L;
		return *this;
	}

	template<typename _Tx> unserial& getvalue(_Tx& v)
	{
		size_t _S = sizeof(v);
		if (_leftsize < _S) throw std::runtime_error("outof range");
		memcpy(&v, _pcur, _S);
		_pcur += _S;
		_leftsize -= _S;
		return *this;
	}

	// don't support ptr, because need usr free ptr
	template<> unserial& getvalue<char*>(char*& v);
	template<> unserial& getvalue<wchar_t*>(wchar_t*& v);
	template<typename _T> unserial& getvalue(const _T*&);
private:
	const char* _pstart;
	const char* _pcur;
	size_t _leftsize;
};

NAMESPACE_END(kog);